package com.udima.reglocation;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MarkerOptions;
import com.udima.reglocation.entities.UserSession;
import com.udima.reglocation.util.AsyncTaskCompleteListener;
import com.udima.reglocation.util.HttpAsyncTask;
import com.udima.reglocation.util.LogHelper;
import com.udima.reglocation.util.PreferencesHandler;
import com.udima.reglocation.util.UserSessionHandler;

/**
 * Clase que permite al usuario visualizar cualquier trayecto de los que están
 * almacenados en el servidor. La información se obtiene con una llamada
 * asíncrona que puede ser de dos maneras: -Sin parámtros de fecha: El servidor
 * devuelve la última ruta almacenada -Conparámetros (fecha inicio - fin): El
 * servidor proporciona un listado de rutas almacenadas en las fechas que
 * cumplen las condiciones del filtrado permitiendo seleccionar una para su
 * posterior visualización en el mapa de Google.
 * 
 * Esta pantalla dispone de un mapa como elemento visual para representar el
 * recorrido que se consulta
 * 
 * @author luis
 * 
 */

public class ListTrackActivity extends android.support.v4.app.FragmentActivity implements AsyncTaskCompleteListener {

	private Activity activity = this;
	private Button btnGetList;
	private EditText inputDateFrom;
	private EditText inputDateTo;

	// Instancia al mapa de Google
	private GoogleMap googleMap;

	private static SimpleDateFormat sdf;
	private static SimpleDateFormat sdfMillis;

	/**
	 * Evento que se lanza en la creación de la clase. Genera el mapa y
	 * posiciona todos los puntos del recorrido que se obtiene del servidor
	 */
	@Override
	@SuppressLint("SimpleDateFormat")
	public void onCreate(Bundle savedInstanceState) {

		sdf = new SimpleDateFormat("dd/MM/yyyy");
		sdf.setTimeZone(TimeZone.getDefault());

		sdfMillis = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss,SSS");
		sdfMillis.setTimeZone(TimeZone.getDefault());

		super.onCreate(savedInstanceState);
		setContentView(R.layout.list_track_activity);

		// Carga del mapa
		initializeMap();
		retrieveGpsData(false);

		btnGetList = (Button) findViewById(R.id.btnGetList);
		inputDateFrom = (EditText) findViewById(R.id.dateFrom);
		inputDateTo = (EditText) findViewById(R.id.dateTo);

		btnGetList.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				retrieveGpsData(true);
			}
		});
	}

	// Función para redondear a dos decimales los double
	private double roundTwoDecimals(double d) {
		String pattern = "#,##";
		DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getNumberInstance(Locale.getDefault());
		decimalFormat.applyPattern(pattern);

		return Double.valueOf(decimalFormat.format(d));
	}

	// Funcion para cargar el mapa
	private void initializeMap() {
		googleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
		googleMap.clear();
		// Comprueba si el mapa se ha creado satisfactoriamente
		if (googleMap == null) {
			Toast.makeText(getApplicationContext(), "Error! no se puede cargar el mapa", Toast.LENGTH_SHORT).show();
		}
	}

	@Override
	protected void onResume() {
		super.onResume();
		if (googleMap == null) {
			initializeMap();
		}
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		googleMap = null;
	};

	@Override
	public void onTaskComplete(String result) {

	}

	/**
	 * 
	 * @param view
	 */
	private void retrieveGpsData(boolean askingForDates) {

		UserSessionHandler ush = new UserSessionHandler(getApplicationContext());
		UserSession session = ush.retrieveUserSession();
		if (session == null) {
			// No hay sesión. Se redirige al usuario a la ventana de login
			Intent i = new Intent(getBaseContext(), LoginActivity.class);
			startActivity(i);
		} else {
			
			PreferencesHandler ph = new PreferencesHandler(getApplicationContext());
			String appBaseUrl = ph.retrieveAppBaseUrl();

			Collection<String> errors = new ArrayList<String>();

			JSONObject jsonReq = new JSONObject();
			JSONObject jsonUserSession = new JSONObject();
			JSONObject jsonGpsFilter = new JSONObject();
			try {
				jsonUserSession.put("userId", session.getUserId());
				jsonUserSession.put("sessionToken", session.getSessionToken());
				jsonReq.put("userSession", jsonUserSession);

				jsonGpsFilter.put("userId", session.getUserId());

				if (askingForDates) {
					// fechas de pantalla
					String dateFrom = inputDateFrom.getText().toString();
					if (!dateFrom.isEmpty()) {
						try {
							Calendar d = Calendar.getInstance();
							d.setTime(sdf.parse(dateFrom));
							d.set(Calendar.HOUR_OF_DAY, 0);
							d.set(Calendar.MINUTE, 0);
							d.set(Calendar.SECOND, 0);
							d.set(Calendar.MILLISECOND, 0);
							jsonGpsFilter.put("initDate", d.getTimeInMillis());
						} catch (ParseException e) {
							errors.add("La fecha desde tiene un formato incorrecto. Utilice dd/mm/aaaa.");
						}
					} else {
						errors.add("Debe indicar la fecha desde");
					}

					String dateTo = inputDateTo.getText().toString();
					if (!dateTo.isEmpty()) {
						try {
							Calendar d = Calendar.getInstance();
							d.setTime(sdf.parse(dateTo));
							d.set(Calendar.HOUR_OF_DAY, 23);
							d.set(Calendar.MINUTE, 59);
							d.set(Calendar.SECOND, 59);
							d.set(Calendar.MILLISECOND, 999);
							jsonGpsFilter.put("endDate", d.getTimeInMillis());
						} catch (ParseException e) {
							errors.add("La fecha hasta tiene un formato incorrecto. Utilice dd/mm/aaaa.");
						}
					} else {
						errors.add("Debe indicar la fecha hasta");
					}
				}

				jsonReq.put("filter", jsonGpsFilter);

			} catch (JSONException e) {
				Toast.makeText(getBaseContext(), "Error grave!! Revise el log de la aplicación", Toast.LENGTH_LONG).show();
				LogHelper.logError("Error parsing json result", e);
			}

			// Definición del callback particular al envio de parámetros de
			// consulta del recorrido
			final AsyncTaskCompleteListener callback = new AsyncTaskCompleteListener() {

				@Override
				public void onTaskComplete(String result) {

					if (HttpAsyncTask.CONNECTIONERROR.equals(result)) {
						Toast.makeText(getBaseContext(), "Error conectando con el servidor", Toast.LENGTH_LONG).show();
					} else {
						try {
							JSONObject json = new JSONObject(result);

							// Si la respuesta ha sido satisfactoria, entonces
							// se procesa el resultado
							if (json.getString("responseSuccessful") == "true") {

								JSONArray jsonGpsData = json.getJSONArray("gpsData");
								JSONObject jsonFilter = json.getJSONObject("filter");

								LatLngBounds.Builder builder = new LatLngBounds.Builder();

								if (jsonGpsData.length() == 0) {
									// no hay posiciones guardadas para las
									// fechas
									// buscadas
									initializeMap();
									if (jsonFilter.getString("initDate") == null) {
										Toast.makeText(getBaseContext(), "No hay rutas guardadas", Toast.LENGTH_LONG).show();
									} else {
										Toast.makeText(getBaseContext(), "No hay rutas guardadas para las fechas seleccionadas", Toast.LENGTH_LONG)
												.show();
									}
								} else {

									// Ponemos la fecha de la respuesta en los
									// input
									// de fechas
									inputDateFrom.setText(sdf.format(new Date(Long.parseLong(jsonFilter.getString("initDate")))));
									inputDateTo.setText(sdf.format(new Date(Long.parseLong(jsonFilter.getString("endDate")))));

									// Bucle para posicionar cada punto del
									// array
									for (int i = 0; i < jsonGpsData.length(); i++) {
										JSONObject p = (JSONObject) jsonGpsData.get(i);

										// Creación del marcador
										String markerTitle = sdfMillis.format(new Date(Long.parseLong(p.getString("fetchTime"))));
										markerTitle += " (" + roundTwoDecimals(Double.parseDouble(p.getString("speedFromPrevious"))) + " km/h)";

										double lat = Double.parseDouble(p.getString("lat"));
										double lon = Double.parseDouble(p.getString("lon"));

										LatLng coords = new LatLng(lat, lon);

										MarkerOptions marker = new MarkerOptions().position(coords);
										marker.title(markerTitle);

										// Se añade el marcador al mapa
										googleMap.addMarker(marker);

										// Se incluye al constructor para el
										// posterior
										// manejo
										builder.include(coords);

									}
								}

								// Procesado del grupo de puntos para ajustar el
								// mapa a estos

								CameraUpdate cu;
								if (jsonGpsData.length() == 0) {
									LatLng coords = new LatLng(0, 0);
									cu = CameraUpdateFactory.newLatLngZoom(coords, 1.0f);
								} else {
									LatLngBounds bounds = builder.build();
									cu = CameraUpdateFactory.newLatLngBounds(bounds, 200);
								}

								googleMap.moveCamera(cu);
								googleMap.animateCamera(cu);

							}
						} catch (JSONException e) {
							Toast.makeText(getBaseContext(), "Error grave!! Revise el log de la aplicación", Toast.LENGTH_LONG).show();
							LogHelper.logError("Error parsing json result", e);
						}
					}
				}
			};

			if (errors.isEmpty()) {
				// Ejecución de la consulta al servicio rest de obtención de
				// recorridos GPS para unas fechas determinadas
				new HttpAsyncTask(activity) {

					@Override
					protected void onPostExecute(String result) {
						super.onPostExecute(result);
						callback.onTaskComplete(result);
					}
				}.execute(appBaseUrl + "/rest/gps/user", jsonReq.toString());
				
			} else {
				Toast.makeText(getBaseContext(), errors.toString(), Toast.LENGTH_LONG).show();
			}

		}
	}

}